/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.mzk.oai.metadataRepository.repository.xmlConfiguration;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Node;
import org.dom4j.XPath;

/**
 * //TODO: test this
 * @author Martin Rehanek (rehan at mzk.cz)
 */
class SetConfigLoader {

    private static String EMPTY_STRING = "";
    private final Set<SetConfig> result = new HashSet<SetConfig>();
    private final Set<String> setSpecsFound = new HashSet<String>();
    private final Set<Integer> idsFound = new HashSet<Integer>();

    private XPath setElementsXpath = DocumentHelper.createXPath("/CollectionsAndSetsMapping/General/OaiSets/Set");
    private XPath setIdXpath = DocumentHelper.createXPath("./@id");
    private XPath setSpecXpath = DocumentHelper.createXPath("./@spec");
    private XPath setNameXpath = DocumentHelper.createXPath("./@name");

    

    public SetConfigLoader(Document doc) throws DocumentException {
        Logger.getLogger(SetConfigLoader.class.getName()).fine("loading sets from configuration file");
        List<Node> setElements = setElementsXpath.selectNodes(doc);
        //System.out.println("sets: " + setElements.size());
        for (Node setElement : setElements) {
            SetConfig configSet = loadConfigSet(setElement);
            //System.out.println(configSet);
            addOaiSetIfOK(configSet);
        }
    }

    /**
     *
     * @return Set of instances of SetConfig with every getSpec() and getId() unique
     */
    Set<SetConfig> getResults() {
        return result;
    }

    private SetConfig loadConfigSet(Node setElement) throws DocumentException {
        try {
            Integer id = loadId(setElement);
            String spec = loadSpec(setElement);
            String name = loadName(setElement);
            return new SetConfig(id,spec,name);
        } catch (Exception e) {
            throw new DocumentException(e);
        }
    }

    private Integer loadId(Node setElement) throws Exception {
        Node node = setIdXpath.selectSingleNode(setElement);
        if (node == null) {
            throw new Exception("no id found");
        }
        return Integer.valueOf(node.getText());
    }

    private String loadSpec(Node setElement) throws Exception {
        return loadNotEmptyAttribute(setSpecXpath, setElement);
    }

    private String loadName(Node setElement) throws Exception {
        return loadNotEmptyAttribute(setNameXpath, setElement);
    }

    private String loadNotEmptyAttribute(XPath xpath, Node setElement) throws Exception {
        Node node = xpath.selectSingleNode(setElement);
        if (node == null) {
            throw new Exception("attribute not found");
        }
        String value = node.getText();
        if (EMPTY_STRING.equals(value)) {
            throw new Exception("attribute is empty");
        }
        return value;
    }

    private void addOaiSetIfOK(SetConfig configSet) throws DocumentException {
        try {
            checkIfUniqueSpec(configSet.getSpec());
            checkIfUniqueId(configSet.getId());
            addOaiSet(configSet);
        } catch (Exception e) {
            throw new DocumentException(e);
        }
    }

    private void checkIfUniqueSpec(String setSpec) throws Exception {
        if (setSpecsFound.contains(setSpec)) {
            throw new Exception("Spec " + setSpec + " already present");
        }
    }

    private void checkIfUniqueId(Integer id) throws Exception {
        if(idsFound.contains(id)){
            throw new Exception("id " + id + " already present");
        }
    }

    private void addOaiSet(SetConfig configSet) {
        setSpecsFound.add(configSet.getSpec());
        idsFound.add(configSet.getId());
        result.add(configSet);
    }
}
